package ez

import (
	"fmt"
	"gitee.com/dreamwood/ez-go/tools"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"time"
)

type MysqlConfig struct {
	Dsn        string `yaml:"dsn"`
	LogLevel   string `yaml:"log-level"`
	logLevel   logger.LogLevel
	LogTo      string `yaml:"log-to"`
	Logger     EzLogger
	FilePath   string        `yaml:"file"`
	MaxOpen    int           `yaml:"max-open"`
	MaxOpenSec time.Duration `yaml:"max-open-sec"`
	MaxIdle    int           `yaml:"max-idle"`
	MaxIdleSec time.Duration `yaml:"max-idle-sec"`
}

func (this *MysqlConfig) UseDefaultLogger() {
	switch this.LogTo {
	case "Nsq":
		this.Logger = LogNsq
	case "File":
		this.Logger = LogFile
	case "Mongo":
		this.Logger = LogMongo
	default:
		this.Logger = LogConsole
	}
}

func (this *MysqlConfig) TransformLogLevel() {

	this.logLevel = logger.Silent
	switch this.LogLevel {
	case "Error":
		this.logLevel = logger.Error
	case "Warn":
		this.logLevel = logger.Warn
	case "Info":
		this.logLevel = logger.Info
	}
}

func LoadMysqlConfig() *MysqlConfig {
	ConfigMysql = new(MysqlConfig)
	tools.CreateConfigFromYml("./app.yaml", "mysql", &ConfigMysql)
	ConfigMysql.UseDefaultLogger()
	ConfigMysql.TransformLogLevel()
	return ConfigMysql
}

type mysqlLogger struct {
	to     string
	logger EzLogger
}

func (l *mysqlLogger) Printf(text string, v ...interface{}) {
	l.logger.Write(fmt.Sprintf(text, v...))
}

func InitMysql() {
	if DBMysql == nil {
		LogToConsoleNoTrace("MYSQL 开始初始化")
		LogToConsoleNoTrace(fmt.Sprintf("数据库链接DSN：%s", ConfigMysql.Dsn))

		myLogger := new(mysqlLogger)
		myLogger.to = ConfigMysql.LogTo
		myLogger.logger = ConfigMysql.Logger
		myLog := logger.New(myLogger, logger.Config{
			SlowThreshold:             200 * time.Millisecond,
			LogLevel:                  ConfigMysql.logLevel,
			IgnoreRecordNotFoundError: false,
			Colorful:                  false,
		})

		gormDB, err := gorm.Open(mysql.New(mysql.Config{
			DSN:                       ConfigMysql.Dsn,
			DefaultStringSize:         256,   // string 类型字段的默认长度
			DisableDatetimePrecision:  false, // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
			DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
			DontSupportRenameColumn:   true,  // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
			SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
		}), &gorm.Config{
			NamingStrategy: schema.NamingStrategy{
				SingularTable: true,
			},
			Logger: myLog,
		})
		if err != nil {
			LogToConsole(fmt.Sprintf("gorm数据库初始化失败:%s", err.Error()))
			return
		}
		sqlDB, err := gormDB.DB()
		if err != nil {
			LogToConsole(fmt.Sprintf("gorm连接池获取失败:%s", err.Error()))
			return
		}
		if sqlDB != nil {
			sqlDB.SetConnMaxIdleTime(ConfigMysql.MaxIdleSec * time.Second)
			sqlDB.SetConnMaxLifetime(ConfigMysql.MaxOpenSec * time.Second)
			sqlDB.SetMaxIdleConns(ConfigMysql.MaxIdle)
			sqlDB.SetMaxOpenConns(ConfigMysql.MaxOpen)
		}
		DBMysql = gormDB
		LogToConsoleNoTrace("MYSQL 初始化完成")
	}
}

// Note 通常该情况使用默认的数据库连接，有时需要同时连接多个数据库，
// 此时需要使用 NewMysqlConfig 和 NewMysqlDb 方法

func NewMysqlConfig(filePath, node string) *MysqlConfig {
	conf := new(MysqlConfig)
	tools.CreateConfigFromYml(filePath, node, &conf)
	conf.UseDefaultLogger()
	conf.TransformLogLevel()
	return conf
}

func NewMysqlDb(mc *MysqlConfig) *gorm.DB {
	LogToConsoleNoTrace("MYSQL 开始初始化")
	mc.TransformLogLevel()
	LogToConsoleNoTrace(fmt.Sprintf("数据库链接DSN：%s", mc.Dsn))

	myLogger := new(mysqlLogger)
	myLogger.to = mc.LogTo
	myLogger.logger = mc.Logger
	myLog := logger.New(myLogger, logger.Config{
		SlowThreshold:             200 * time.Millisecond,
		LogLevel:                  mc.logLevel,
		IgnoreRecordNotFoundError: false,
		Colorful:                  false,
	})

	gormDB, err := gorm.Open(mysql.New(mysql.Config{
		DSN:                       mc.Dsn,
		DefaultStringSize:         256,   // string 类型字段的默认长度
		DisableDatetimePrecision:  false, // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,  // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
	}), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
		},
		Logger: myLog,
	})
	if err != nil {
		LogToConsole(fmt.Sprintf("gorm数据库初始化失败:%s", err.Error()))
		return nil
	}
	sqlDB, err := gormDB.DB()
	if err != nil {
		LogToConsole(fmt.Sprintf("gorm连接池获取失败:%s", err.Error()))
		return nil
	}
	if sqlDB != nil {
		sqlDB.SetConnMaxIdleTime(mc.MaxIdleSec * time.Second)
		sqlDB.SetConnMaxLifetime(mc.MaxOpenSec * time.Second)
		sqlDB.SetMaxIdleConns(mc.MaxIdle)
		sqlDB.SetMaxOpenConns(mc.MaxOpen)
	}
	LogToConsoleNoTrace("MYSQL 初始化完成")
	return gormDB
}
